package cn.agiledata.bank.transaction.facade;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpSession;

import cn.agiledata.bank.account.dao.IAccountDAO;
import cn.agiledata.bank.common.util.Constant;
import cn.agiledata.bank.common.util.PageBean;
import cn.agiledata.bank.common.util.WebUtil;
import cn.agiledata.bank.hibernateBean.Account;
import cn.agiledata.bank.hibernateBean.PeerBankAccount;
import cn.agiledata.bank.hibernateBean.PeerInnerAccount;
import cn.agiledata.bank.hibernateBean.SubAccount;
import cn.agiledata.bank.myspace.bean.PeerBankAccountQueryBean;
import cn.agiledata.bank.myspace.bean.PeerInnerAccountQueryBean;
import cn.agiledata.bank.myspace.service.PeerAccountService;
import cn.agiledata.bank.transaction.exception.TransactionException;
import cn.agiledata.bank.transaction.form.BatchPayForm;
import cn.agiledata.bank.transaction.logic.BatchPeerAccount;
import cn.agiledata.bank.transaction.logic.PeerAccountAmount;
import cn.agiledata.bank.transaction.logic.PeerBankAccountWrapper;
import cn.agiledata.bank.transaction.logic.PeerInnerAccountWrapper;
import cn.agiledata.bank.transaction.service.TransactionService;

public class TransactionFacadeImpl implements TransactionFacade {
    private IAccountDAO accountDao;

    private TransactionService transactionService;

    private PeerAccountService peerAccountService;

    public void setAccountDao(IAccountDAO accountDao) {
        this.accountDao = accountDao;
    }

    public void setTransactionService(TransactionService transactionService) {
        this.transactionService = transactionService;
    }

    public void setPeerAccountService(PeerAccountService peerAccountService) {
        this.peerAccountService = peerAccountService;
    }

    public PageBean getPeerAccountList(Long accountId,
            BatchPeerAccount batchPeerAccount, String startPage,
            String pageRecord) {
        if (batchPeerAccount.isInnerBatchPeerAccount()) {
            PeerInnerAccountQueryBean queryBean = new PeerInnerAccountQueryBean();
            queryBean.setAccountId(accountId);
            queryBean.setStartPage(startPage);
            queryBean.setPageRecord(pageRecord);
            PageBean pb = this.peerAccountService
                    .getPeerInnerAccountList(queryBean);
            List peerAccountList = pb.getData();
            for (int i = 0; i < peerAccountList.size(); i++) {
                PeerInnerAccount peerAccount = (PeerInnerAccount) peerAccountList
                        .get(i);
                // 封装
                PeerInnerAccountWrapper peerAccountWrapper = new PeerInnerAccountWrapper(
                        peerAccount);
                long peerAccountId = peerAccount.getId().longValue();
                PeerAccountAmount paa = batchPeerAccount.get(peerAccountId);
                if (paa != null) { // 如果交易对方账户已被设置，则将设置信息保存到封装对象中
                    peerAccountWrapper.setSelected(true);
                    peerAccountWrapper.setAmount(paa.getAmount());
                    peerAccountWrapper.setFee(paa.getFee());
                }
                // 用封装对象替代原逻辑对象
                peerAccountList.set(i, peerAccountWrapper);
            }
            return pb;
        } else {
            PeerBankAccountQueryBean queryBean = new PeerBankAccountQueryBean();
            queryBean.setAccountId(accountId);
            queryBean.setStartPage(startPage);
            queryBean.setPageRecord(pageRecord);
            PageBean pb = this.peerAccountService
                    .getPeerBankAccountList(queryBean);
            List peerAccountList = pb.getData();
            for (int i = 0; i < peerAccountList.size(); i++) {
                PeerBankAccount peerAccount = (PeerBankAccount) peerAccountList
                        .get(i);
                // 封装
                PeerBankAccountWrapper peerAccountWrapper = new PeerBankAccountWrapper(
                        peerAccount);
                long peerAccountId = peerAccount.getId().longValue();
                PeerAccountAmount paa = batchPeerAccount.get(peerAccountId);
                if (paa != null) { // 如果交易对方账户已被设置，则将设置信息保存到封装对象中
                    peerAccountWrapper.setSelected(true);
                    peerAccountWrapper.setAmount(paa.getAmount());
                    peerAccountWrapper.setFee(paa.getFee());
                }
                // 用封装对象替代原逻辑对象
                peerAccountList.set(i, peerAccountWrapper);
            }
            return pb;
        }
    }

    public PageBean getPeerAccountAmountList(BatchPeerAccount batchPeerAccount,
            int startPage, int pageRecord) {
        PageBean pb = new PageBean();
        List data = new ArrayList();
        int totalCount = batchPeerAccount.getCount(); // 总记录数
        int beginIndex = (startPage - 1) * pageRecord; // 起始索引
        if (beginIndex < totalCount) { // 起始索引大于总记录数则直接返回空列表
            if (beginIndex < 0) {
                beginIndex = 0; // 起始索引如果小于0，则默认从0索引处开始查询
            }
            int endIndex = startPage * pageRecord; // 终止索引
            if (endIndex > totalCount) {
                endIndex = totalCount; // 终止索引如果大于总记录数，则以总记录数为终止索引
            }
            PeerAccountAmount[] paas = batchPeerAccount.getValues();
            if (batchPeerAccount.isInnerBatchPeerAccount()) { // 账户
                for (int i = beginIndex; i < endIndex; i++) {
                    PeerInnerAccount peerAccount = this.peerAccountService
                            .getPeerInnerAccount(paas[i].getId());
                    PeerInnerAccountWrapper peerAccountWrapper = new PeerInnerAccountWrapper(
                            peerAccount);
                    peerAccountWrapper.setSelected(true);
                    peerAccountWrapper.setAmount(paas[i].getAmount());
                    peerAccountWrapper.setFee(paas[i].getFee());
                    data.add(peerAccountWrapper);
                }
            } else {
                for (int i = beginIndex; i < endIndex; i++) { // 银行账户
                    PeerBankAccount peerAccount = this.peerAccountService
                            .getPeerBankAccount(paas[i].getId());
                    PeerBankAccountWrapper peerAccountWrapper = new PeerBankAccountWrapper(
                            peerAccount);
                    peerAccountWrapper.setSelected(true);
                    peerAccountWrapper.setAmount(paas[i].getAmount());
                    peerAccountWrapper.setFee(paas[i].getFee());
                    data.add(peerAccountWrapper);
                }
            }
        }
        // 按时间排倒序
        Collections.sort(data, new Comparator() {
            public int compare(Object o1, Object o2) {
                if (o1 instanceof PeerInnerAccountWrapper
                        && o2 instanceof PeerInnerAccountWrapper) {
                    PeerInnerAccountWrapper paw1 = (PeerInnerAccountWrapper) o1;
                    PeerInnerAccountWrapper paw2 = (PeerInnerAccountWrapper) o2;
                    return paw2.getUpdateTime().compareTo(paw1.getUpdateTime());
                }
                if (o1 instanceof PeerBankAccountWrapper
                        && o2 instanceof PeerBankAccountWrapper) {
                    PeerBankAccountWrapper paw1 = (PeerBankAccountWrapper) o1;
                    PeerBankAccountWrapper paw2 = (PeerBankAccountWrapper) o2;
                    return paw2.getUpdateTime().compareTo(paw1.getUpdateTime());
                }
                return 0;
            }
        });
        pb.setData(data);
        pb.setTotalCount(totalCount);
        pb.setTotalPage(totalCount % pageRecord == 0 ? totalCount / pageRecord
                : totalCount / pageRecord + 1);
        pb.setPrevious((startPage - 1 < 1) ? 1 : startPage - 1);
        pb.setCurPage(startPage);
        pb.setNext((startPage + 1 > pb.getTotalPage()) ? pb.getTotalPage()
                : startPage + 1);
        pb.setLength(pageRecord);
        return pb;
    }

    public BigDecimal validateAmount(String amount) throws TransactionException {
        try {
            return new BigDecimal(amount);
        } catch (RuntimeException e) {
            throw TransactionException.INVALID_AMOUT;
        }
    }

    public SubAccount validateBalance(long debitSubAccountId, BigDecimal amount)
            throws TransactionException {
        SubAccount subAccount = this.accountDao.getSubAccountById(new Long(
                debitSubAccountId));
        Double balance = subAccount.getAccountBalance().getBalance();
        if (balance.doubleValue() < amount.doubleValue()) { // 余额不足
            throw TransactionException.LACK_OF_BALANCE;
        }
        return subAccount;
    }

    /**
     * 
     * @return session中的BatchPayForm
     */
    private BatchPayForm getBatchPayForm() {
        HttpSession session = WebUtil.getSession();
        Map attributeMap = WebUtil.getSessionAttributesByClass(session,
                BatchPayForm.class);
        // session中应该只有一个BatchPayForm，多余的不考虑
        return (BatchPayForm) attributeMap.values().iterator().next();
    }

    public PeerAccountAmount savePeerAccountAmount(long peerAccountId,
            String amount) {
        BatchPayForm form = getBatchPayForm();
        BatchPeerAccount bpa = form == null ? null : form.getBatchPeerAccount();
        if (bpa == null) { // session过期
            return null;
        }
        String actionType = bpa.isInnerBatchPeerAccount() ? Constant.ACTION_TYPE_C
                : Constant.ACTION_TYPE_G;
        SubAccount debit = this.accountDao.getSubAccountById(new Long(form
                .getSubAccountId()));
        try {
            BigDecimal validatedAmount = validateAmount(amount);
            if (validatedAmount.setScale(2, BigDecimal.ROUND_HALF_UP)
                    .doubleValue() > 0) {
                BigDecimal fee = this.transactionService.getDebitFee(debit,
                        actionType, validatedAmount).setScale(2,
                        BigDecimal.ROUND_HALF_UP);
                return bpa.put(peerAccountId, validatedAmount, fee);
            }
            return null;
        } catch (TransactionException e) {
            return null;
        }
    }

    public BatchPeerAccount removePeerAccountAmount(long peerAccountId) {
        BatchPeerAccount bpa = getBatchPeerAccount();
        if (bpa == null) { // session过期
            return null;
        }
        bpa.remove(peerAccountId);
        return bpa;
    }

    public BatchPeerAccount getBatchPeerAccount() {
        BatchPayForm form = getBatchPayForm();
        return form == null ? null : form.getBatchPeerAccount();
    }

    public String getFeeModeDescription(Account account, String actionType) {
        return this.transactionService.getFeeModeDescription(account,
                actionType);
    }


}
